package com.shareroad.dubboweb.frame.util;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.alibaba.fastjson.JSON;
import com.shareroad.dubboweb.client.annotation.DubboField;
import com.shareroad.dubboweb.client.annotation.DubboMethod;
import com.shareroad.dubboweb.client.annotation.DubboModel;
import com.shareroad.dubboweb.client.annotation.DubboParam;
import com.shareroad.dubboweb.client.annotation.DubboWeb;
import com.shareroad.dubboweb.frame.dao.po.DubboEnumPO;
import com.shareroad.dubboweb.frame.dao.po.DubboFieldPO;
import com.shareroad.dubboweb.frame.dao.po.DubboInterfacePO;
import com.shareroad.dubboweb.frame.dao.po.DubboMethodPO;
import com.shareroad.dubboweb.frame.dao.po.DubboModelPO;
import com.shareroad.dubboweb.frame.dao.po.DubboParamPO;
import com.shareroad.dubboweb.frame.dao.po.DubboWebPO;
import com.shareroad.dubboweb.frame.model.entity.ErrorCode;

public class JarUtil {

	public static DubboWebPO parseJar(String jarPath, ClassLoader loader) {
		JarFile jarFile = null;
		DubboWebPO dubboWebPO = new DubboWebPO();
		try {
			File file = new File(jarPath);
			dubboWebPO.jarName = file.getName();
			jarFile = new JarFile(file);// 读入jar文件
			List<DubboInterfacePO> interfaceList = new ArrayList<DubboInterfacePO>();
			List<DubboModelPO> modelList = new ArrayList<DubboModelPO>();
			List<DubboEnumPO> enumList = new ArrayList<DubboEnumPO>();

			Enumeration<JarEntry> en = jarFile.entries(); // 枚举获得JAR文件内的实体,即相对路径
			while (en.hasMoreElements()) { // 遍历显示JAR文件中的内容信息
				JarEntry jentry = en.nextElement(); // 调用方法显示内容
				if (!jentry.getName().endsWith(".class")) {
					continue;
				}
				String clazzPath = jentry.getName().replace("/", ".").replace(".class", "");
				Class<?> cl = Class.forName(clazzPath, false, loader);
				
				if (cl.isInterface()) { //接口
					DubboInterfacePO dubboInterface = new DubboInterfacePO();
					dubboInterface.packageName = cl.getPackage().getName();
					dubboInterface.interfaceName = cl.getName();
					DubboWeb interfaceAnno = (DubboWeb) cl.getAnnotation(DubboWeb.class);
					if (null != interfaceAnno) {
						dubboInterface.interfaceDesc = interfaceAnno.desc();
					}

					List<DubboMethodPO> methodList = new ArrayList<DubboMethodPO>();
					Method[] methods = cl.getDeclaredMethods();
					for (Method mth : methods) {
						DubboMethodPO dubboMethod = new DubboMethodPO();
						DubboMethod methodAnno = mth.getAnnotation(DubboMethod.class);
						if (null != methodAnno) {
							dubboMethod.methodDesc = methodAnno.desc();
						}
						dubboMethod.accessType = Modifier.toString(mth
								.getModifiers());
						dubboMethod.returnType = mth.getReturnType().getName();
						dubboMethod.methodName = mth.getName();
						List<DubboParamPO> paramList = new ArrayList<DubboParamPO>();
						Parameter[] params = mth.getParameters();
						for (Parameter param : params) {
							DubboParamPO dubboParam = new DubboParamPO();
							DubboParam paramAnno = param.getAnnotation(DubboParam.class);
							if (null != paramAnno) {
								dubboParam.name = paramAnno.name();
								dubboParam.desc = paramAnno.desc();
							}
							dubboParam.sourceName = param.getName();
							dubboParam.type = param.getType().getName();
							paramList.add(dubboParam);
						}
						dubboMethod.dubboParamList = paramList;
						methodList.add(dubboMethod);
					}
					dubboInterface.dubboMethodList = methodList;
					interfaceList.add(dubboInterface);
					
				} else if(cl.isEnum()){ //枚举
					
					DubboEnumPO dubboEnum = new DubboEnumPO();
					dubboEnum.name = cl.getName();
					DubboModel modelAnno = (DubboModel) cl.getAnnotation(DubboModel.class);
					if (null != modelAnno) {
						dubboEnum.desc = modelAnno.desc();
					}
					Object[] enums = cl.getEnumConstants();
					List<String> enumValues = new ArrayList<String>();
					if(null != enums){
						for(Object o : enums){
							enumValues.add(o.toString());
						}
					}
					dubboEnum.constants = enumValues;
					enumList.add(dubboEnum);
					
				} else if (cl.isAnnotation()) { // 注解
					//todo null;
					
				} else { // class 
					DubboModelPO model = new DubboModelPO();
					model.name = cl.getName();
					DubboModel modelAnno = (DubboModel) cl.getAnnotation(DubboModel.class);
					if (null != modelAnno) {
						model.desc = modelAnno.desc();
					}
					Field[] fields = null ;
					try{
						fields = cl.getDeclaredFields();
					}catch(Exception e){
						e.printStackTrace();
					}
					
					if (null != fields) {
						List<DubboFieldPO> mfieldList = new ArrayList<DubboFieldPO>();
						for (Field f : fields) {
							f.setAccessible(true);
							DubboFieldPO df = new DubboFieldPO();
							df.accessType = Modifier.toString(f.getModifiers());
							df.name = f.getName();
							df.type = f.getType().getName();
							DubboField fieldAnno = f.getAnnotation(DubboField.class);
							if (null != fieldAnno) {
								df.desc = fieldAnno.desc();
							}
							mfieldList.add(df);
						}
						model.fieldList = mfieldList;
						modelList.add(model);
					}
				}

			}
			dubboWebPO.dubboInterfaceList = interfaceList;
			dubboWebPO.dubboModelList = modelList;
			dubboWebPO.dubboEnumList = enumList ;
		} catch (Exception e) {
			e.printStackTrace();
			dubboWebPO.errorCode = ErrorCode.api_parse_jar_error.getCode();
			dubboWebPO.errorDesc = ErrorCode.api_parse_jar_error.getDesc();
		} finally {
			try {
				jarFile.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return dubboWebPO;
	}
	
	@SuppressWarnings({ "resource" })
	public static URLClassLoader loadJar(String jarPath,ClassLoader loader) throws Exception{
		File file = new File(jarPath);
		//
		URLClassLoader urlLoader = new URLClassLoader(new URL[] { file.toURI().toURL() },loader);
		JarFile jarFile = new JarFile(file);//读入jar文件 
		Enumeration<JarEntry> en = jarFile.entries(); // 枚举获得JAR文件内的实体,即相对路径
		while (en.hasMoreElements()) { // 遍历显示JAR文件中的内容信息
			JarEntry jentry = en.nextElement(); // 调用方法显示内容
			if(!jentry.getName().endsWith(".class")){
				continue;
			}
			String clazzPath = jentry.getName().replace("/", ".").replace(".class", "");
			urlLoader.loadClass(clazzPath);
		}
		return urlLoader;
		
	}

	public static ClassLoader getDubboWebClassLoader() {
		return Thread.currentThread().getContextClassLoader();
	}

	public static void main(String[] args) throws Exception {
		String path = "D:/api/";
		File file = new File(path);
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		for (File f : file.listFiles()) {
			if(!f.getName().endsWith(".jar")){
				continue;
			}
			System.out.println(f.getPath());
			URLClassLoader uloader = JarUtil.loadJar(f.getPath(), loader);
			System.out.println(JSON.toJSONString(JarUtil.parseJar(f.getPath(),
					uloader)));
		}
	}

}
